package com.example.wexcle.demos.web.controller;
import com.example.wexcle.demos.web.R;
import com.example.wexcle.demos.web.config.ListPartitioner;
import com.example.wexcle.demos.web.entity.File;
import com.example.wexcle.demos.web.service.ExcelExportService;
import com.example.wexcle.demos.web.service.IUserService;
import com.example.wexcle.demos.web.service.TydkFile;
import com.example.wexcle.demos.web.service.TydkOss;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@RestController
@RequestMapping("/excle")
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class DownloadController {

    @Autowired
    private ExcelExportService excelExportService;
    @Autowired
    private IUserService iUserService;
    @Autowired
    private TydkOss tydkOss;
    @Autowired
    private TydkFile tydkFile;

    File file = new File();

    /**
     * 循环往数据库插入100w数据
     */
    @ApiOperation("向数据库循环插入百万数据")
    @PostMapping("/add100w")
    public void add100w() {
        for (int i = 1; i <= 1000000; i++) {


            file.setId(i);
            file.setCount(10000);
            file.setFilename(i + ".txt");
            file.setLocaladdress("C:\\testuser");
            file.setState("0");
            iUserService.save(file);

        }
    }

    /**
     * 将100万数据从数据库导出并压缩上传oss,返回文件地址
     * @return
     * @throws Exception
     */
    @ApiOperation("导出百万数据接口压缩上传oss(返回文件地址)")
        @GetMapping("/download")
//        public ResponseEntity<byte[]> exportToZip() throws Exception直接返回流
    public String  exportToZip() throws Exception {
            long beginTime = System.currentTimeMillis();
            //  创建临时数据
//        List<File> dataList = createDataList(100);
            //查询数据库数据
            List<File> dataList = iUserService.list();
            List<List<File>> dataSets = ListPartitioner.partition(dataList, 10);
            // 使用方法
//        List<List<Integer>> partitionedList = ListPartitioner.partition(dataList, 10);
            List<CompletableFuture<String>> futures = new ArrayList<>();
            //  异步导出所有Excel文件
            String outputDir = "D:\\data";
            for (List<File> dataSet : dataSets) {
                futures.add(excelExportService.exportDataToExcel(dataSet, outputDir));//
            }

            //  等待所有导出任务完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0])).get(10, TimeUnit.MINUTES);

            //  收集Excel文件路径
            List<String> excelFilePaths = futures.stream()
                    .map(CompletableFuture::join)
                    .collect(Collectors.toList());

            //  压缩文件
            java.io.File zipFile = new java.io.File("D:\\data\\output.zip");
            try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {

                for (String filePath : excelFilePaths) {
                    zipFile(new java.io.File(filePath), zipOut, new java.io.File(filePath).getName());
                }
            }
            // 删除临时文件
            for (String filePath : excelFilePaths) {
                java.io.File file = new java.io.File(filePath);
                file.delete();
            }

            //  返回ZIP文件
            byte[] data = Files.readAllBytes(zipFile.toPath());
            //上传本地的压缩包，返回链接地址以便于客户端下载
            R localoss = tydkOss.localoss("D:\\data\\output.zip");
            //删除本地文件，防止下次导出失效
            zipFile.delete();
            System.out.println("导出文件耗时："+(System.currentTimeMillis() - beginTime)/1000+"----------");

            return (String) localoss.getData().get("url");
            //返回流数据，结合上面返回方法可用
//            return ResponseEntity.ok()
//                    .header("Content-Disposition", "attachment;  filename=\"" + zipFile.getName() + "\"")
//                    .contentType(MediaType.parseMediaType("application/zip"))
//                    .body(data);
        }

        //  将文件添加到ZIP输出流中
        private void zipFile(java.io.File file, ZipOutputStream zipOut, String entryName) throws IOException {
//        tydkOss.uploadOssFile2();
            try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {

                ZipEntry zipEntry = new ZipEntry(entryName);
                zipOut.putNextEntry(zipEntry);
                byte[] bytesIn = new byte[4096];
                int read;
                while ((read = bis.read(bytesIn)) != -1) {
                    zipOut.write(bytesIn, 0, read);
                }
                zipOut.closeEntry();
            }
        }

}